package ast

import (
	"fmt"
	"strings"

	"gitee.com/u-language/u-language/ucom/astdata"
	"gitee.com/u-language/u-language/ucom/enum"
	"gitee.com/u-language/u-language/ucom/errcode"
	"gitee.com/u-language/u-language/ucom/internal/utils"
	"gitee.com/u-language/u-language/ucom/lex"
)

// check_name 检查一个标识符是否合法
func check_name(name string) errcode.ErrCode {
	if ok := check_is_type(name); ok { //有类型声明保留字
		return errcode.NameRetain
	}
	return errcode.NoErr //没有问题
}

// check_is_type 检查是否是内置类型
func check_is_type(name string) bool {
	_, ok := TypeEnumStrMap[name]
	return ok
}

// FuncInfo 函数信息
type FuncInfo struct {
	Name       string
	FileName   string
	Parame     []astdata.Parame
	RetValue   []astdata.RetValue
	TypeParame []astdata.NameAndType
	LineNum    int
}

func (f *FuncInfo) String() string {
	return fmt.Sprintf("%+v", *f)
}

func (f *FuncInfo) Copy() *FuncInfo {
	ret := *f
	ret.Parame = copyNameAndTyp(ret.Parame)
	ret.RetValue = copyNameAndTyp(ret.RetValue)
	ret.TypeParame = copyNameAndTyp(ret.TypeParame)
	return &ret
}

func (f *FuncInfo) genName() string {
	list := typInfoToStr(f.Parame)
	s := utils.GenerateGenericTypes(f.Name, list)
	return s
}

// check_func_decl 检查函数或方法声明
// 假设函数末尾是左大括号
func check_func_decl(t *Tree, line *lex.Line, err errcode.ErrCode) *FuncInfo {
	code := check_func_decl_err(line)
	if code != errcode.NoErr {
		t.Panic(line, nil, err, code)
		return nil
	}
	var ok bool
	ret := new(FuncInfo)
	ret.Name, ret.TypeParame, ok = parserName(t, &line.Value[1], line, err, ret)
	if !ok {
		return nil
	}
	if strings.HasSuffix(ret.Name, enum.AutoFreeInFunc) { //如果结尾是_mempool
		t.Panic(line, nil, err, errcode.EndOfNameCannot_mempool)
		return nil
	}
	ret.Parame, ret.RetValue, code = check_func_Parame(t, line, err, ret)
	if code != errcode.NoErr {
		t.Panic(line, nil, err, code)
		return nil
	}
	ret.LineNum, ret.FileName = line.Linenum, t.Filename
	return ret
}

// check_func_decl_err 检查函数声明的错误
// 实现假定 line.Value[0].TYPE==FUNC
func check_func_decl_err(line *lex.Line) errcode.ErrCode {
	Rbraceok := false
	for i := 1; i < len(line.Value); i++ {
		switch i {
		case 1: //语法规定应该出现函数名的位置
			if !isName(line.Value[i].TYPE) {
				return errcode.NoName
			}
		case 2: //语法规定应该出现左小括号的位置
			if line.Value[i].TYPE != lex.LPAREN {
				return errcode.EmptyLPAREN
			}
		default:
			if line.Value[i].TYPE == lex.RPAREN { //语法规定应该有一个右小括号
				Rbraceok = true
			}
		}
	}
	if !Rbraceok { //如果没有右小括号
		return errcode.EmptyRPAREN
	}
	return errcode.NoErr
}

// check_lex_LBRACE 检查左大括号是否在同一行末尾
func check_lex_LBRACE(t *Tree, line *lex.Line, code errcode.ErrCode) (ok bool) {
	if li := len(line.Value); line.Value[li-1].TYPE != lex.LBRACE { //左大括号不在同一行最后
		t.Panic(line, nil, code, errcode.LbraceEndOfLine)
		return false
	}
	return true
}

// check_func_Parame 检查函数的参数列表
func check_func_Parame(t *Tree, line *lex.Line, err errcode.ErrCode, FuncInfo *FuncInfo) ([]astdata.Parame, []astdata.RetValue, errcode.ErrCode) {
	llen := len(line.Value) - 1
	var pret = make([]astdata.Parame, 0, llen/2)
	var rret = make([]astdata.RetValue, 0, 1)
	name, isret, comma := "", false, 0
	// 对于func funcname(参数列表)[{] 从词法分析结果偏移量3开始
	for i := 3; i < llen; i++ {
		switch line.Value[i].TYPE {
		case lex.NAME, lex.LEA, lex.MoreThanJustTokensWithBrackts:
			if isret { //目前只支持单返回值
				rret = append(rret, astdata.NewNameAndType("", parserTypeName(t, line, &line.Value[i], err, FuncInfo)))
				return pret, rret, errcode.NoErr
			}
			if name == "" { //是名称
				name = line.Value[i].Value
				if strings.HasPrefix(name, enum.Generate) {
					return nil, nil, errcode.NameCannotStartWithGenerate
				}
				continue
			}
			pret = append(pret, astdata.NewNameAndType(name, parserTypeName(t, line, &line.Value[i], err, FuncInfo)))
			name, comma = "", 0
		case lex.Comma: //是逗号
			if name != "" {
				return nil, nil, errcode.ParameDeclHasNoType
			}
			comma++
			if comma != 1 { //参数之间有不在一个逗号
				return nil, nil, errcode.UnexpectedComma
			}
		case lex.RPAREN:
			isret = true
		default:
			return nil, nil, errcode.OPbug
		}
	}
	if name != "" {
		return nil, nil, errcode.ParameDeclHasNoType
	}
	return pret, rret, errcode.NoErr
}

// check_struct_field 检查结构体字段
func check_struct_field(t *Tree, line []lex.Line, FuncInfo *FuncInfo) []Field {
	if len(line) == 0 {
		return nil
	}
	llen := len(line)
	ret := make([]Field, 0, llen)
	for i := 0; i < llen; i++ {
		length := len(line[i].Value)
		if length != 2 && length != 0 { //如果不是 name type 同时非空
			t.Panic(&line[i], nil, errcode.StructErr, errcode.FieldErr, errcode.OPbug)
			continue
		}
		if length == 0 { //如果是空行
			continue
		}
		if !check_is_type_token(line[i].Value[0].TYPE) || !check_is_type_token(line[i].Value[1].TYPE) {
			t.Panic(&line[i], nil, errcode.StructErr, errcode.FieldErr, errcode.NoIdent)
			continue
		}
		err := check_name(line[i].Value[0].Value)
		if err != errcode.NoErr { //如果名称或类型有错误
			t.Panic(&line[i], nil, errcode.StructErr, errcode.FieldErr, err)
			continue
		}
		ret = append(ret, astdata.NewNameAndType(line[i].Value[0].Value, parserTypeName(t, &line[i], &line[i].Value[1], errcode.StructErr, FuncInfo)))
	}
	return ret
}

// check_is_type_token 检查是否是类型可能的token类型
func check_is_type_token(typ lex.TokenType) bool {
	return typ == lex.NAME || typ == lex.LEA || typ == lex.MoreThanJustTokensWithBrackts
}

// check_enums 检查结构体字段
func check_enums(t *Tree, line []lex.Line) []string {
	llen := len(line)
	if llen == 0 {
		return nil
	}
	ret, m := make([]string, 0, llen), utils.MapSet.Get().(map[string]struct{})
	for i := 0; i < llen; i++ {
		if len(line[i].Value) == 0 { //如果是空行
			continue
		}
		if len(line[i].Value) != 1 { //如果不是 name
			t.Panic(&line[i], nil, errcode.EnumErr, errcode.EnumValueShouldHaveOneOnEachLine)
			continue
		}
		if line[i].Value[0].TYPE != lex.NAME { //如果不是符号
			t.Panic(&line[i], nil, errcode.EnumErr, errcode.EnumValueShouldBeASymbol)
			continue
		}
		_, ok := m[line[i].Value[0].Value]
		if ok {
			t.Panic(&line[i], errcode.NewMsgSymbol(line[i].Value[0].Value), errcode.EnumErr, errcode.EnumValueDup)
		} else {
			m[line[i].Value[0].Value] = struct{}{}
		}
		ret = append(ret, line[i].Value[0].Value)
	}
	utils.PutMapSet(m)
	return ret
}

// check_TypeParame 检查类型参数列表
func check_TypeParame(t *Tree, tk *lex.Token, line *lex.Line, err errcode.ErrCode, FuncInfo *FuncInfo) ([]astdata.NameAndType, string) {
	tks := *tk.PtrMoreThanJustTokensWithBracktsS().Ptr //Note:tks[0].Value不可能不是符号
	var ret = make([]astdata.NameAndType, 0, len(tks[1].Value)/3)
	// 对于 类型参数列表，去除中括号，按逗号分割
	list := strings.Split(ret_middle_str(tks[1].Value), ",") //Note:似乎len(list)不可能为0
	for _, v := range list {
		one_tks := lex_scan(t, v, line)
		if len(one_tks) != 2 { //如果不是 name 约束
			t.Panic(line, nil, errcode.TypeParameSyntaxErr)
			continue
		}
		typ := parserTypeName(t, line, &one_tks[1], err, FuncInfo)
		if utils.IsNil(typ) { //如果类型参数约束为空
			t.Panic(line, nil, errcode.TypeParamrConstraintErr)
			continue
		}
		ret = append(ret, astdata.NewNameAndType(utils.GeneratePackageSymbol(t.PackageName, one_tks[0].Value), typ))
	}
	return ret, tks[0].Value
}

// check_from_list 检查泛型实例化列表
//
// 设输入=list , 输出=ret
// 当 list=T ,ret=T
// 当 list=T,S ret=T S
// 当 list=S[T,S] ret=S[T,S]
// 当 list=S[T,S],T ret=S[T,S] T
func check_from_list(list string) []string {
	var ret []string
	var match leftRightMatch
	left, llen := 0, len(list)
	for i := 0; i < llen; i++ {
		switch list[i] {
		case '[':
			match.leftNum++
		case ']':
			match.rightNum++
			if match.Ok() {
				ret = append(ret, list[left:i+1])
				left, match.leftNum, match.rightNum = i+1, 0, 0
			}
		case ',':
			if match.leftNum == 0 {
				if left != i {
					ret = append(ret, list[left:i])
				}
				left = i + 1
			}
		}
	}
	if left < llen {
		ret = append(ret, list[left:])
	}
	return ret
}
